/**
 * @file w25q64.c
 * @author leijiapeng (email:leijiapeng123@163.com)
 * @brief
 * @version 0.1
 * @date 2025-09-26
 *
 * @copyright Copyright (c) 2025
 *
 */

#include "w25qxx.h"
#include "spi.h"
#include "w25qxx_ins.h"

// W25QXX_s w25q128 = {
//     .MID         = W25Q128_MID,
//     .DID         = W25Q128_DID,
//     .PageSize    = W25Q128_PAGE_SIZE,
//     .PageCount   = W25Q128_PAGE_COUNT,
//     .SectorSize  = W25Q128_SECTOR_SIZE,
//     .SectorCount = W25Q128_SECTOR_COUNT,
//     .BlockSize   = W25Q128_BLOCK_SIZE,
//     .BlockCount  = W25Q128_BLOCK_COUNT,
//     .Capacity    = W25Q128_CAPACITY,
// };

/**
 * @brief  W25QXX初始化
 *
 */
void W25QXX_Init(void)
{
    MySPI_Init(); // 先初始化底层的SPI
}

/**
 * @brief  读取ID号
 *
 * @param[out] MID 厂商ID
 * @param[out] DID 设备ID
 */
void W25QXX_ReadID(uint8_t *MID, uint16_t *DID)
{
    MySPI_Start();                             // SPI起始
    MySPI_SwapByte(W25QXX_JEDEC_ID);           // 交换发送读取ID的指令
    *MID = MySPI_SwapByte(W25QXX_DUMMY_BYTE);  // 交换接收MID，通过输出参数返回
    *DID = MySPI_SwapByte(W25QXX_DUMMY_BYTE);  // 交换接收DID高8位
    *DID <<= 8;                                // 高8位移到高位
    *DID |= MySPI_SwapByte(W25QXX_DUMMY_BYTE); // 或上交换接收DID的低8位，通过输出参数返回
    MySPI_Stop();                              // SPI终止
}

/**
 * @brief  W25QXX写使能
 *
 */
void W25QXX_WriteEnable(void)
{
    MySPI_Start();                       // SPI起始
    MySPI_SwapByte(W25QXX_WRITE_ENABLE); // 交换发送写使能的指令
    MySPI_Stop();                        // SPI终止
}

/**
 * @brief  等待忙
 *
 */
void W25QXX_WaitBusy(void)
{
    uint32_t Timeout;
    MySPI_Start();                                             // SPI起始
    MySPI_SwapByte(W25QXX_READ_STATUS_REGISTER_1);             // 交换发送读状态寄存器1的指令
    Timeout = 100000;                                          // 给定超时计数时间
    while ((MySPI_SwapByte(W25QXX_DUMMY_BYTE) & 0x01) == 0x01) // 循环等待忙标志位
    {
        Timeout--;        // 等待时，计数值自减
        if (Timeout == 0) // 自减到0后，等待超时
        {
            /*超时的错误处理代码，可以添加到此处*/
            break; // 跳出等待，不等了
        }
    }
    MySPI_Stop(); // SPI终止
}

/**
 * @brief  W25QXX页编程
 *
 * @param[in] Address       页编程的起始地址，范围：0x000000\~0x7FFFFF，如果是W25Q128，则最大范围是0xFFFFFF
 * @param[in] DataArray     用于写入数据的数组
 * @param[in] Count         要写入数据的数量，范围：0\~256
 */
void W25QXX_PageProgram(uint32_t Address, uint8_t *DataArray, uint16_t Count)
{
    uint16_t i;

    W25QXX_WriteEnable(); // 写使能

    MySPI_Start();                       // SPI起始
    MySPI_SwapByte(W25QXX_PAGE_PROGRAM); // 交换发送页编程的指令
    MySPI_SwapByte(Address >> 16);       // 交换发送地址23~16位
    MySPI_SwapByte(Address >> 8);        // 交换发送地址15~8位
    MySPI_SwapByte(Address);             // 交换发送地址7~0位
    for (i = 0; i < Count; i++)          // 循环Count次
    {
        MySPI_SwapByte(DataArray[i]); // 依次在起始地址后写入数据
    }
    MySPI_Stop(); // SPI终止

    W25QXX_WaitBusy(); // 等待忙
}

/**
 * @brief  W25QXX扇区擦除（4KB）
 *
 * @param[in] addr   指定扇区的地址，范围：0x000000~0x7FFFFF，如果是W25Q128，则最大范围是0xFFFFFF
 */
void W25QXX_SectorErase(uint32_t addr)
{
    uint32_t Address = addr & W25QXX_ERASE_SECTOR_MASK;

    W25QXX_WriteEnable(); // 写使能

    MySPI_Start();                           // SPI起始
    MySPI_SwapByte(W25QXX_SECTOR_ERASE_4KB); // 交换发送扇区擦除的指令
    MySPI_SwapByte(Address >> 16);           // 交换发送地址23~16位
    MySPI_SwapByte(Address >> 8);            // 交换发送地址15~8位
    MySPI_SwapByte(Address);                 // 交换发送地址7~0位
    MySPI_Stop();                            // SPI终止

    W25QXX_WaitBusy(); // 等待忙
}

/**
 * @brief  读取数据
 *
 * @param[in]  Address      读取数据的起始地址，范围：0x000000\~0x7FFFFF，如果是W25Q128，则最大范围是0xFFFFFF
 * @param[out] DataArray    用于接收读取数据的数组
 * @param[in]  Count        要读取数据的数量，范围：0\~0x800000
 */
void W25QXX_ReadData(uint32_t Address, uint8_t *DataArray, uint32_t Count)
{
    uint32_t i;
    MySPI_Start();                    // SPI起始
    MySPI_SwapByte(W25QXX_READ_DATA); // 交换发送读取数据的指令
    MySPI_SwapByte(Address >> 16);    // 交换发送地址23~16位
    MySPI_SwapByte(Address >> 8);     // 交换发送地址15~8位
    MySPI_SwapByte(Address);          // 交换发送地址7~0位
    for (i = 0; i < Count; i++)       // 循环Count次
    {
        DataArray[i] = MySPI_SwapByte(W25QXX_DUMMY_BYTE); // 依次在起始地址后读取数据
    }
    MySPI_Stop(); // SPI终止
}

/**
 * @brief  将扇区编号转换为地址
 *
 * @param[in] sector 扇区编号，范围[0, W25Q128_SECTOR_COUNT]
 * @return uint32_t 扇区编号对应的首地址
 */
uint32_t sector_to_address(uint32_t sector)
{
    // 验证扇区编号有效性（可选）
    if (sector >= W25Q128_SECTOR_COUNT)
    {
        // 错误处理：扇区编号超出范围
        return 0xFFFFFFFF; // 返回无效地址
    }
    return sector * W25Q128_SECTOR_SIZE;
}

/**
 * @brief  将页编号转换为地址
 *
 * @param[in] page 页编号，范围[0, W25Q128_PAGE_COUNT]
 * @return uint32_t 页编号对应的首地址
 */
uint32_t page_to_address(uint32_t page)
{
    // 验证页号有效性
    if (page >= W25Q128_PAGE_COUNT)
    {
        return 0xFFFFFFFF; // 返回无效地址表示错误
    }
    return page * W25Q128_PAGE_SIZE;
}